import { IToken } from './token';

export { IToken };

/**
 * 词法分析器配置类型
 *
 * @interface ILexerConfig
 */
interface ILexerConfig {
  /**
   * 类型： whitespace、word、operator
   *
   * @type {string}
   * @memberof ILexerConfig
   */
  type: string;
  /**
   * 分词正则
   *
   * @type {RegExp[]}
   * @memberof ILexerConfig
   */
  regexes: RegExp[];
  /**
   * Will match, by not add to token list.
   * 不添加进入token列表，如：whitespace
   * @type {boolean}
   * @memberof ILexerConfig
   */
  ignore?: boolean;
}

/**
 * 分词器
 *
 * @class Tokenizer
 */
class Tokenizer {
  // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-parameter-properties
  constructor(public lexerConfig: ILexerConfig[]) {
    //
  }

  /**
   * 分词方法
   *
   * @param {string} input SQL语句
   * @return {Array<IToken>} tokens
   * @memberof Tokenizer
   */
  public tokenize(input: string) {
    const tokens = [];
    let token: IToken;
    // SQL语句已经分词的定位
    let lastPosition = 0;

    // 继续处理字符串，直到它为空
    while (input.length) {
      // 获取下一个token和token类型
      const result = this.getNextToken(input);

      if (!result || !result.token) {
        throw Error(`Lexer: Unexpected string "${input}".`);
      }

      // eslint-disable-next-line prefer-destructuring
      token = result.token;

      if (!token.value) {
        throw Error(`[Lexer]词法分析器: 正则解析错误，请检查您的词法分析器配置.`);
      }

      // [tokenStartPositon, tokenEndPosition]
      token.position = [lastPosition, lastPosition + token.value.length - 1];
      lastPosition += token.value.length;

      // 剪切字符串，保证input是未处理的
      // eslint-disable-next-line no-param-reassign
      input = input.substring(token.value.length);

      // ILexerConfig.ignore配置
      if (!result.config.ignore) {
        tokens.push(token);
      }
    }
    return tokens;
  }

  /**
   * 向下分析词法，继续分词
   *
   * @private
   * @param {string} input
   * @return {Object|null}
   * @memberof Tokenizer
   */
  private getNextToken(input: string) {
    // 每个不同的type上的正则表达式组
    for (const eachLexer of this.lexerConfig) {
      //
      for (const regex of eachLexer.regexes) {
        const token = this.getTokenOnFirstMatch({ input, type: eachLexer.type, regex });
        if (token) {
          return {
            token,
            config: eachLexer,
          };
        }
      }
    }

    return null;
  }

  // 匹配一个结果立即返回
  private getTokenOnFirstMatch({ input, type, regex }: { input: string; type: string; regex: RegExp }) {
    const matches = input.match(regex);

    if (matches) {
      /*
        正则都是使用的分组
        const myLexer = createLexer([
          {
            type: 'whitespace',
            regexes: [/^(\s+)/],
            ignore: true
          },
          {
            type: 'word',
            regexes: [/^([a-zA-Z0-9]+)/]
          },
          {
            type: 'operator',
            regexes: [/^(\+)/]
          }
        ]);
      */
      // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
      return { type, value: matches[1] } as IToken;
    }
  }
}

export type Lexer = (text: string) => IToken[];

/**
 * 创建词法分析器
 * @export
 * @param {ILexerConfig[]} lexerConfig 词法分析配置，进行词法分析
 * @return {*}  {Lexer}
 */
export const createLexer = (lexerConfig: ILexerConfig[]): Lexer => {
  return (text: string) => {
    //
    return new Tokenizer(lexerConfig).tokenize(text);
  };
};
